package com.hmkj.core.service.account.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.hmkj.common.baseMapper.GenericMapper;
import com.hmkj.common.utils.DateUtils;
import com.hmkj.common.utils.OrderNoUtils;
import com.hmkj.common.utils.StringUtils;
import com.hmkj.core.api.lianlian.PartnerConfig;
import com.hmkj.core.api.lianlian.PayDataBean;
import com.hmkj.core.api.lianlian.PaymentInfo;
import com.hmkj.core.api.lianlian.PaymentInfo2;
import com.hmkj.core.api.lianlian.enums.PayResultEnum;
import com.hmkj.core.api.lianlian.util.YinTongUtil;
import com.hmkj.core.constant.CacheID;
import com.hmkj.core.constant.ConfigNID;
import com.hmkj.core.constant.PointNid;
import com.hmkj.core.exception.BussinessException;
import com.hmkj.core.mapper.account.AccountLogMapper;
import com.hmkj.core.mapper.account.AccountMapper;
import com.hmkj.core.mapper.account.AccountRechargeMapper;
import com.hmkj.core.mapper.user.UserMapper;
import com.hmkj.core.mapper.userBank.UserBankMapper;
import com.hmkj.core.model.pay.PayResult;
import com.hmkj.core.po.account.Account;
import com.hmkj.core.po.account.AccountLog;
import com.hmkj.core.po.account.AccountRecharge;
import com.hmkj.core.po.user.User;
import com.hmkj.core.po.userAuth.UserAuth;
import com.hmkj.core.po.userBank.UserBank;
import com.hmkj.core.service.account.AccountRechargeService;
import com.hmkj.core.service.cache.RedisService;
import com.hmkj.core.service.userAuth.UserAuthService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.Date;
import java.util.Objects;

/**
 * 充值记录业务相关Service接口实现<br>
 *
 * @author eproo
 * @ClassName: AccountRechargeServiceImpl
 * @date 2018-07-05 09:50:54
 */
@Slf4j
@Service
@Scope("prototype")
@Transactional(rollbackFor = Exception.class)
public class AccountRechargeServiceImpl implements AccountRechargeService {

    @Resource
    private RedisService redisService;
    @Resource
    private UserAuthService userAuthService;
    @Resource
    private AccountRechargeMapper accountRechargeMapper;
    @Resource
    private UserMapper userMapper;
    @Resource
    private AccountMapper accountMapper;
    @Resource
    private AccountLogMapper accountLogMapper;
    @Resource
    private UserBankMapper userBankMapper;

    @Override
    public GenericMapper<AccountRecharge, Integer> _getMapper() {
        return accountRechargeMapper;
    }

    @Override
    public PaymentInfo2  doRechargeByLianLian(HttpServletRequest req, Integer userId, Integer bankId, String hmTk, String amount) {
        User user = userMapper.selectByPrimaryKey(userId);
        UserAuth userAuth = userAuthService.selectByUID(user.getId());
        if (null == userAuth || userAuth.getAuthStatus() != UserAuth.AUTHSTATUS.CERTIFICATED.code) {
            throw new BussinessException("您先实名认证");
        }
        UserBank bank = userBankMapper.selectByPrimaryKey(bankId);
        if (bank == null) {
            throw new BussinessException("充值银行卡未绑定");
        }

        // 新增充值记录
        AccountRecharge recharge = new AccountRecharge();
        recharge.setUserId(user.getId());
        recharge.setOrderNo(OrderNoUtils.getLLRechargeOrderNo());
        recharge.setAmount(new BigDecimal(amount));
        recharge.setType(AccountRecharge.TYPE.T1.code);
        recharge.setRemark(hmTk);
        recharge.setStatus(AccountRecharge.STATUS.T1.code);
        if (accountRechargeMapper.insert(recharge) != 1) {
            throw new BussinessException("保存充值记录失败");
        }

        // 构造支付请求对象
        PaymentInfo2 paymentInfo = new PaymentInfo2();
        paymentInfo.setVersion(PartnerConfig.VERSION);
        paymentInfo.setOid_partner(PartnerConfig.OID_PARTNER);
        paymentInfo.setUser_id(user.getId().toString());
//        paymentInfo.setApp_request(PartnerConfig.WAP);
        paymentInfo.setSign_type(PartnerConfig.SIGN_TYPE);
        paymentInfo.setBusi_partner(PartnerConfig.BUSI_PARTNER);
        paymentInfo.setNo_order(recharge.getOrderNo());
        paymentInfo.setDt_order(DateUtils.dateStr(new Date(), "yyyyMMddHHmmss"));
        paymentInfo.setName_goods("购买商品");
        paymentInfo.setInfo_order(hmTk);
        paymentInfo.setMoney_order(amount);
        paymentInfo.setPay_type("P");
        String webUrl = redisService.get(ConfigNID.WEB_SERVER_URL);
        paymentInfo.setNotify_url(webUrl + PartnerConfig.NOTIFY_URL);
        paymentInfo.setUrl_return(webUrl + "result?hm_tk=" + hmTk);
        paymentInfo.setUserreq_ip(YinTongUtil.getIpAddr(req).replaceAll("\\.", "_"));//用户端申请 IP
        paymentInfo.setUrl_order("");//订单地址
        //        paymentInfo.setBack_url(webUrl + "my");
        paymentInfo.setValid_order("10080");// 单位分钟，可以为空，默认7天
        paymentInfo.setRisk_item(createRiskItem(user, userAuth));
        paymentInfo.setTimestamp(YinTongUtil.getCurrentDateTimeStr());
        // 商戶从自己系统中获取用户身份信息(认证支付必须将用户身份信息传输给连连，且修改标记flag_modify设置成1：不可修改)
        paymentInfo.setId_type("0");
        paymentInfo.setId_no(userAuth.getIdcard());
        paymentInfo.setAcct_name(userAuth.getRealname());
        paymentInfo.setFlag_modify("1");
//        if (StringUtils.isNotBlank(noAgree)) { // 协议号和卡号同时存在时，优先将协议号送给连连，不要将协议号和卡号都送给连连
//           paymentInfo.setNo_agree(noAgree);
//        }
        paymentInfo.setCard_no(bank.getBankNo());
        paymentInfo.setApp_request("3");
        paymentInfo.setBack_url(webUrl);
        // 加签名
        String sign = YinTongUtil.addSign(JSON.parseObject(JSON.toJSONString(paymentInfo)), PartnerConfig.TRADER_PRI_KEY, PartnerConfig.MD5_KEY);
        paymentInfo.setSign(sign);

        return paymentInfo;

    }

    @Override
    public void handleRechargeByLianLian(PayDataBean payDataBean) {
        try {
            // 主要业务参数判断
            if (StringUtils.isBlank(payDataBean.getMoney_order()) || StringUtils.isBlank(payDataBean.getOid_paybill())) {
                log.error("处理订单参数缺失,终止处理...");
                throw new BussinessException("处理订单参数缺失,终止处理...");
            }
            // 通过订单号 用户id查询充值订单
            AccountRecharge recharge = this.findByUserIdAndOrderNo(payDataBean.getNo_order());
            if (recharge == null) {
                throw new BussinessException("充值订单不存在。");
            }
            if (recharge.getStatus().intValue() == AccountRecharge.STATUS.T3.code) {
                throw new BussinessException("充值订单已处理，订单ID：" + recharge.getId());
            }
            if (Objects.equals(PayResultEnum.SUCCESS.getCode(), payDataBean.getResult_pay())) {
                //判断订单状态和订单金额
                if (recharge.getStatus() != AccountRecharge.STATUS.T3.code) {
                    // 实际到账金额
                    BigDecimal amount = new BigDecimal(payDataBean.getMoney_order());

                    // 处理用户资金和记录资金日志
                    Account account = accountMapper.selectByUID(recharge.getUserId());
                    if (account == null) {
                        throw new BussinessException("查询用户资金账户失败");
                    }
                    //资金记录
                    AccountLog accountLog = AccountLog.buildLog(account.getUserId(), 0, amount, AccountLog.TYPE.T1, account, "快捷支付入金：" + amount + "元");
                    if (accountLogMapper.insert(accountLog) != 1) {
                        throw new BussinessException("充值保存资金记录失败");
                    }
                    //更新账户资金
                    if(accountMapper.updateAccount(amount, amount, BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO, account.getUserId()) != 1){
                        throw new BussinessException("充值保存资金记录失败");
                    }

                    //处理充值订单
                    recharge.setActualArrival(amount);
                    recharge.setUpdateTime(new Date());
                    recharge.setRemark("连连支付充值成功");
                    recharge.setStatus(AccountRecharge.STATUS.T3.code);
                    recharge.setOutOrderNo(payDataBean.getOid_paybill());
                    recharge.setOutStatus(payDataBean.getResult_pay());
                    recharge.setOutMsg(JSON.toJSONString(payDataBean));
                    accountRechargeMapper.updateByPrimaryKeySelective(new AccountRecharge(t -> {
                        t.setId(recharge.getId());
                        t.setActualArrival(amount);
                        t.setUpdateTime(new Date());
                        t.setRemark("连连支付充值成功");
                        t.setStatus(AccountRecharge.STATUS.T3.code);
                        t.setOutOrderNo(payDataBean.getOid_paybill());
                        t.setOutStatus(payDataBean.getResult_pay());
                        t.setOutMsg(JSON.toJSONString(payDataBean));
                    }));

                    // 缓存回调结果
                    redisService.put(CacheID.PAY_RESULT + payDataBean.getInfo_order(), PayResult.success("恭喜您，充值成功", ""), 30 * 60);
                } else {
                    log.error("充值订单已处理，订单ID：" + recharge.getId());
                }
            } else {
                //处理充值订单
                accountRechargeMapper.updateByPrimaryKeySelective(new AccountRecharge(t -> {
                    t.setId(recharge.getId());
                    t.setActualArrival(BigDecimal.ZERO);
                    t.setUpdateTime(new Date());
                    t.setRemark("连连支付充值失败");
                    t.setStatus(AccountRecharge.STATUS.T4.code);
                    t.setOutStatus(payDataBean.getResult_pay());
                    t.setOutMsg(JSON.toJSONString(payDataBean));
                }));
                recharge.setActualArrival(BigDecimal.ZERO);
                recharge.setUpdateTime(new Date());
                recharge.setOutStatus(payDataBean.getResult_pay());
                recharge.setRemark("连连支付充值失败");
                recharge.setStatus(AccountRecharge.STATUS.T4.code);
                recharge.setOutMsg(JSON.toJSONString(payDataBean));
                accountRechargeMapper.updateByPrimaryKeySelective(recharge);

                redisService.put(CacheID.PAY_RESULT + payDataBean.getInfo_order(), PayResult.failed("抱歉，充值失败", ""), 30 * 60);
            }
        }catch (BussinessException e) {
            e.printStackTrace();
            redisService.put(CacheID.PAY_RESULT + payDataBean.getInfo_order(), PayResult.failed(e.getMessage(), ""), 30 * 60);
            throw e;
        } catch (Exception e) {
            e.printStackTrace();
            redisService.put(CacheID.PAY_RESULT + payDataBean.getInfo_order(), PayResult.failed("系统繁忙，请到账户中心核对", ""), 30 * 60);
            throw e;
        }
    }

    @Override
    public AccountRecharge findByUserIdAndOrderNo(String orderId) {
        if (StringUtils.isBlank(orderId)) {
            throw new BussinessException("查询订单参数缺失");
        }
        return accountRechargeMapper.findByUserIdAndOrderNo(orderId);
    }

    /**
     * 根据连连支付风控部门要求的参数进行构造风控参数
     *
     * @return
     */
    private String createRiskItem(User user, UserAuth userAuth) {
        JSONObject riskItemObj = new JSONObject();
        riskItemObj.put("frms_ware_category", "2026");//商品类目
        riskItemObj.put("user_info_mercht_userno", String.valueOf(user.getId()));//你们平台的用户id
        riskItemObj.put("user_info_dt_register", DateUtils.dateStr3(user.getCreateTime()));//注册时间
        riskItemObj.put("user_info_bind_phone", user.getMobilePhone());//绑定手机号
        if (StringUtils.isNotBlank(userAuth.getRealname())) {
            riskItemObj.put("user_info_identify_state", "1");//已经实名认证
        } else {
            riskItemObj.put("user_info_identify_state", "0");//没有实名认证
        }
        riskItemObj.put("user_info_identify_state", "1");//已经实名认证
        riskItemObj.put("user_info_identify_type", "1");//实名认证方式
        riskItemObj.put("user_info_full_name", userAuth.getRealname());//用户姓名
        riskItemObj.put("user_info_id_no", userAuth.getIdcard());//用户身份证号
        return riskItemObj.toString();
    }

    @Override
    public void addRechargeMoney(AccountRecharge accountRecharge) throws Exception {

        //参数效验
        if (accountRecharge == null) {
            throw new BussinessException("参数有误");
        }
        User user = userMapper.selectByPrimaryKey(accountRecharge.getUserId());
        if (user == null) {
            throw new BussinessException("客户不存在");
        }
        if (accountRecharge.getAmount().compareTo(BigDecimal.ZERO) != 1) {
            throw new BussinessException("充值金额必须大于0");
        }
        if (StringUtils.isBlank(accountRecharge.getOrderNo())) {
            throw new BussinessException("流水号不能为空");
        }
        if (accountRecharge.getOrderNo().length() > 50) {
            throw new BussinessException("流水号长度不能超过50位");
        }
        if (StringUtils.isBlank(accountRecharge.getRemark())) {
            throw new BussinessException("备注不能为空");
        }
        if (accountRecharge.getRemark().length() > 200) {
            throw new BussinessException("备注长度不能超过200位");
        }
        Account account = accountMapper.selectByUID(accountRecharge.getUserId());

        accountRechargeMapper.insert(new AccountRecharge(t -> {
            t.setUserId(accountRecharge.getUserId());
            t.setType(AccountRecharge.TYPE.T4.code);
            t.setAmount(accountRecharge.getAmount());
            t.setFee(BigDecimal.ZERO);
            t.setRemark(accountRecharge.getRemark());
            t.setOrderNo(accountRecharge.getOrderNo());
            t.setStatus(AccountRecharge.STATUS.T3.code);
        }));

        //资金记录
        AccountLog accountLog = AccountLog.buildLog(accountRecharge.getUserId(), 0, accountRecharge.getAmount(), AccountLog.TYPE.T1, account, "手动入金：" + accountRecharge.getAmount() + "元");
        if(accountLogMapper.insert(accountLog) != 1){
            throw new BussinessException("手动入金失败");
        }
        //更新账户资金
        if(accountMapper.updateAccount(accountRecharge.getAmount(), accountRecharge.getAmount(), BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO, accountRecharge.getUserId()) !=1){
            throw new BussinessException("手动入金失败");
        }
    }

}
